#ifndef __CUHB_SVEC_HPP__
#define __CUHB_SVEC_HPP__

struct vec {
    float x, y, z;
};

static inline vec make_vec(float x, float y, float z) {
    vec ret = {x, y, z};
    return ret;
}

struct Svec {
    Config m_cfg;

    size_t m_volume;
    size_t m_pad;
    size_t m_stride;
    size_t m_replicas;

    size_t m_gpu_bytes;
    void*  m_gpu_buf;

    size_t m_cpu_bytes;
    void*  m_cpu_buf;

    Svec(Config &conf, int pad, int replicas = 1);
    ~Svec();
    size_t replicas() { return m_replicas; }
    void init(float x, float y, float z);
    void init(const vec &v);
    void cpu_to_gpu();
    void gpu_to_cpu();
    bool check_norm() const;
    float calc_alignment(const vec &dir) const;
    void dump() const;

    float4 at(int ix, int iy, int iz) const {
        //const int lx = m_cfg.lat[DIR_X];
        const int ly = m_cfg.lat[DIR_Y];
        const int lz = m_cfg.lat[DIR_Z];
        return ((float4*)m_cpu_buf)[iz + lz*(iy + ix*ly)];
    }

    const vec operator()(int ix, int iy, int iz) const {
        float4 v = at(ix, iy, iz);
        vec r = { v.x, v.y, v.z };
        return r;
    }

    void set(int ix, int iy, int iz, const vec& v) {
        //const int lx = m_cfg.lat[DIR_X];
        const int ly = m_cfg.lat[DIR_Y];
        const int lz = m_cfg.lat[DIR_Z];
        ((float4*)m_cpu_buf)[iz + lz*(iy + ix*ly)] = make_float4(v.x, v.y, v.z, 0.0f);
    }

protected:
    void init_r1(float x, float y, float z);
    void init_r2(float x, float y, float z);
    void init_r4(float x, float y, float z);
};

struct Jmat;
float calc_energy(const Svec& v, const Jmat&j);

/*
 * Local variables:
 *  mode: c++
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 *  indent-tabs-mode: nil
 * End:
 */

#endif // __CUHB_SVEC_HPP__
